﻿/**
 * 客户端类的构造方法。
 */
function Client() {
    const mConnectedEvent = document.createEvent("customEvent")             // 网络连接完成事件
    const mEventChatC2S = document.createEvent("customEvent")               // 聊天事件（客户端到服务器）
    const mEventChatS2C = document.createEvent("customEvent")               // 聊天事件（服务器到客户端）
    const mEventFriendLogoff = document.createEvent("customEvent")          // 得到好友离线事件
    const mEventFriendLogon = document.createEvent("customEvent")           // 得到好友登录事件
    const mEventGetAddFriendRequest = document.createEvent("customEvent")   // 得到添加好友请求事件
    const mEventGetAddFriendResult = document.createEvent("customEvent")    // 得到添加好友结果事件
    const mEventGetLogonResult = document.createEvent("customEvent")        // 得到登录结果事件
    const mEventGetRegResult = document.createEvent("customEvent")          // 得到注册结果事件
    var mFriendCount = 0                                                    // 好友数
    var mIconIndex = 0                                                      // 头像索引
    const mSocket = new WebSocket("WS://" + SERVER_IP + ":" + SERVER_PORT)  // 套接字

    // 初始化成员
    mConnectedEvent.initEvent(Const.UM_CONNECTED, false, false)
    mEventChatC2S.initEvent(Const.UM_CHAT_C2S, false, false)
    mEventChatS2C.initEvent(Const.UM_CHAT_S2C, false, false)
    mEventGetAddFriendRequest.initEvent(Const.UM_GET_ADD_FRIEND_REQUEST, false, false)
    mEventGetAddFriendResult.initEvent(Const.UM_GET_ADD_FRIEND_RESULT, false, false)
    mEventGetLogonResult.initEvent(Const.UM_GET_LOGON_RESULT, false, false)
    mEventGetRegResult.initEvent(Const.UM_GET_REG_RESULT, false, false)
    mEventFriendLogoff.initEvent(Const.UM_FRIEND_LOGOFF, false, false)
    mEventFriendLogon.initEvent(Const.UM_FRIEND_LOGON, false, false)
    mSocket.onopen = onConnected
    mSocket.onerror = onError
    mSocket.onmessage = onReceive

    /**
     * 添加好友。
     * @param friendName  好友名字
     * @return 结果
     */
    this.addFriend = function(friendName) {
        // 检查是否超过好友上限
        if (mFriendCount > Const.MAX_USER_COUNT) {
            return ResultCode.TOO_MANY_FRIENDS
        }

        // 检查好友名
        if (friendName == Client.sUsername) {
            return ResultCode.FRIEND_NAME_EQUAL_SELF_NAME
        }

        // 发送添加好友请求
        const request = new AddFriendRequest(friendName, mIconIndex, Client.sUsername)
        try {
            sendData(request)
        } catch (e) {
            return ResultCode.NETWORK_ERROR
        }

        return ResultCode.SUCCEEDED
    }

    /**
     * 允许或拒绝添加好友。
     * @param allow     允许则为 true，否则为 false
     * @param request   添加好友请求
     */
    this.allowAddFriend = function(allow, request) {
        // 发送结果
        const addFriendResult = new AddFriendResult(mIconIndex, request.mDstUsername,
            allow ? ResultCode.ADD_FRIEND_ALLOW: ResultCode.ADD_FRIEND_NOT_ALLOW, request.mSrcUsername)
        sendData(addFriendResult)

        // 如果允许，则好友数加1
        if (allow) {
            mFriendCount++
        }
    }

    /**
     * 聊天。
     * @param chatInfo  聊天信息
     */
    this.chat = function(chatInfo) {
        sendData(chatInfo)
    }

    /**
     * 关闭客户端。
     */
    this.close = function() {
        // 离线
        this.logoff()
        
        // 关闭
        mSocket.close()
    }

    /**
     * 获取好友数。
     * @return 好友数
     */
    this.getFriendCount = function() {
        return mFriendCount
    }

    /**
     * 处理添加好友请求。
     * @param request   添加好友请求
     */
    function handleAddFriendRequest(request) {
        mEventGetAddFriendRequest.arg1 = request
        document.dispatchEvent(mEventGetAddFriendRequest)
    }

    /**
     * 处理添加好友结果。
     * @param result    添加好友结果
     */
    function handleAddFriendResult(result) {
        if (result.mResultCode == ResultCode.ADD_FRIEND_ALLOW && result.mDstIconIndex != -1) {
            mFriendCount++
        }

        mEventGetAddFriendResult.arg1 = result
        document.dispatchEvent(mEventGetAddFriendResult)
    }

    /**
     * 处理聊天。
     * @param chatInfo  聊天信息
     */
    function handleChat(chatInfo) {
        mEventChatS2C.arg1 = chatInfo
        document.dispatchEvent(mEventChatS2C)
    }

    /**
     * 处理其他用户的离线请求。
     * @param request   其他用户的离线请求
     */
    function handleFriendLogoff(request) {
        mEventFriendLogoff.arg1 = request
        document.dispatchEvent(mEventFriendLogoff)
    }

    /**
     * 处理其他用户的登录消息。
     * @param friendLogon   其他用户的登录消息
     */
    function handleFriendLogon(friendLogon) {
        mEventFriendLogon.arg1 = friendLogon
        document.dispatchEvent(mEventFriendLogon)
    }

    /**
     * 处理登录结果。
     * @param result    登录结果
     */
    function handleLogonResult(result) {
        mEventGetLogonResult.arg1 = result
        document.dispatchEvent(mEventGetLogonResult)

        if (result.mResultCode == ResultCode.LOGON_SUCCEEDED) {
            mIconIndex = result.mIconIndex
            mFriendCount = result.mFriendCount
        } else {
            Client.sUsername = ""
        }
    }

    /**
     * 处理注册结果。
     * @param result    注册结果
     */
    function handleRegResult(result) {
        mEventGetRegResult.arg1 = result
        document.dispatchEvent(mEventGetRegResult)

        if (result.mResultCode != ResultCode.REG_SUCCEEDED) {
            Client.sUsername = ""
        }
    }

    /**
     * 离线。
     * @return 结果
     */
    this.logoff = function() {
        if (Client.sUsername == "") {
            return
        }

        const request = new LogoffRequest(Client.sUsername)
        sendData(request)

        Client.sUsername = ""
    }

    /**
     * 登录。
     * @param username  用户名
     * @param password  密码
     */
    this.logon = function(username, password) {
        // 发送登录请求
        const request = new LogonRequest(password, username)
        sendData(request)

        // 保存用户名
        Client.sUsername = username
    }

    /**
     * 网络连接完成事件的响应方法。
     */
    function onConnected() {
        mConnectedEvent.arg1 = true
        document.dispatchEvent(mConnectedEvent)
    }

    /**
     * 网络错误事件的响应方法。
     */
    function onError() {
        mConnectedEvent.arg1 = false
        document.dispatchEvent(mConnectedEvent)
    }

    /**
     * 接收到数据的响应方法。
     * @param data  数据
     */
    function onReceive(data) {
        // 将数据转换成协议
        const pro = JSON.parse(data.data)

        // 处理协议
        switch (pro.mType) {
            case ProtocolType.ADD_FRIEND_REQUEST:
                handleAddFriendRequest(pro)
                break 
            case ProtocolType.ADD_FRIEND_RESULT:
                handleAddFriendResult(pro)
                break 
            case ProtocolType.CHAT:
                handleChat(pro)
                break 
            case ProtocolType.FRIEND_LOGON:
                handleFriendLogon(pro)
                break 
            case ProtocolType.LOGOFF:
                handleFriendLogoff(pro)
                break 
            case ProtocolType.LOGON:
                handleLogonResult(pro)
                break 
            case ProtocolType.REG:
                handleRegResult(pro)
                break 
        }
    }

    /**
     * 注册。
     * @param username  用户名
     * @param password  密码
     * @param iconIndex 头像索引
     * @return 结果
     */
    this.reg = function(username, password, iconIndex) {
        // 发送注册请求
        const request = new RegRequest(iconIndex, password, username)
        sendData(request)

        // 保存用户名和头像索引
        Client.sUsername = username
        mIconIndex = iconIndex
    }

    /**
     * 发送数据。
     * @param pro   协议
     */
    function sendData(pro) {
        const text = JSON.stringify(pro)
        mSocket.send(text)
    }
}

Client.sUsername = ""   // 用户名
